home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / utils / cache / relcache.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-06  |  32.4 KB  |  1,240 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    relcache.c 
  4.  *    
  5.  *   DESCRIPTION
  6.  *    POSTGRES relation descriptor cache code
  7.  *
  8.  *   INTERFACE ROUTINES
  9.  *    RelationInitialize        - initialize relcache
  10.  *    RelationIdCacheGetRelation    - get a reldesc from the cache (id)
  11.  *    RelationNameCacheGetRelation    - get a reldesc from the cache (name)
  12.  *    RelationIdGetRelation        - get a reldesc by relation id
  13.  *    RelationNameGetRelation        - get a reldesc by relation name
  14.  *    RelationClose            - close an open relation
  15.  *    RelationFlushRelation        - flush relation information
  16.  *
  17.  *   NOTES
  18.  *    This file is in the process of being cleaned up
  19.  *    before I add system attribute indexing.  -cim 1/13/91
  20.  *
  21.  *    The following code contains many undocumented hacks.  Please be
  22.  *    careful....
  23.  *
  24.  *   IDENTIFICATION
  25.  *    $Header: /private/postgres/src/utils/cache/RCS/relcache.c,v 1.64 1992/08/25 22:24:00 mao Exp $
  26.  * ----------------------------------------------------------------
  27.  */
  28. #include <errno.h>
  29. #include <sys/file.h>
  30. #include <strings.h>
  31.  
  32. /* XXX check above includes */
  33.  
  34. #include "tmp/postgres.h"
  35.  
  36. RcsId("$Header: /private/postgres/src/utils/cache/RCS/relcache.c,v 1.64 1992/08/25 22:24:00 mao Exp $");
  37.  
  38. #include "access/att.h"
  39. #include "access/attnum.h"
  40. #include "access/genam.h"
  41. #include "access/heapam.h"
  42. #include "access/htup.h"
  43. #include "access/istrat.h"
  44. #include "access/itup.h"
  45. #include "access/skey.h"
  46. #include "access/tqual.h"    /* for NowTimeQual */
  47. #include "access/tupdesc.h"
  48.  
  49. #include "rules/rlock.h"
  50. #include "storage/buf.h"
  51. #include "storage/lmgr.h"
  52.  
  53. #include "tmp/hasht.h"
  54.  
  55. #include "utils/memutils.h"
  56. #include "utils/log.h"
  57. #include "utils/mcxt.h"
  58. #include "utils/rel.h"
  59. #include "utils/hsearch.h"
  60.  
  61. #include "catalog/catname.h"
  62. #include "catalog/syscache.h"
  63.  
  64. #include "catalog/pg_attribute.h"
  65. #include "catalog/pg_aggregate.h"
  66. #include "catalog/pg_index.h"
  67. #include "catalog/pg_proc.h"
  68. #include "catalog/pg_relation.h"
  69. #include "catalog/pg_type.h"
  70.  
  71. #include "catalog/pg_variable.h"
  72. #include "catalog/pg_log.h"
  73. #include "catalog/pg_time.h"
  74.  
  75. #include "utils/relcache.h"
  76.  
  77. #ifdef sprite
  78. #include "sprite_file.h"
  79. #else
  80. #include "storage/fd.h"
  81. #endif /* sprite */
  82.  
  83. /* ----------------
  84.  *    defines
  85.  * ----------------
  86.  */
  87. #define private static
  88.  
  89. /* ----------------
  90.  *    externs
  91.  * ----------------
  92.  */
  93. extern bool    AMI_OVERRIDE;    /* XXX style */
  94.  
  95. /* ----------------
  96.  *    hardcoded tuple descriptors.  see lib/H/catalog/pg_attribute.h
  97.  * ----------------
  98.  */
  99. SCHEMA_DEF(pg_relation);
  100. SCHEMA_DEF(pg_attribute);
  101. SCHEMA_DEF(pg_proc);
  102. SCHEMA_DEF(pg_type);
  103. SCHEMA_DEF(pg_variable);
  104. SCHEMA_DEF(pg_log);
  105. SCHEMA_DEF(pg_time);
  106.  
  107. /* ----------------
  108.  *    global variables
  109.  *
  110.  *     Relations are cached two ways, by name and by id,
  111.  *    thus there are two hash tables for referencing them. 
  112.  * ----------------
  113.  */
  114. HTAB     *RelationNameCache;
  115. HTAB    *RelationIdCache;
  116.  
  117. /* ----------------
  118.  *    RelationBuildDescInfo exists so code can be shared
  119.  *      between RelationIdGetRelation() and RelationNameGetRelation()
  120.  * ----------------
  121.  */
  122. typedef struct RelationBuildDescInfo {
  123.     int infotype;        /* lookup by id or by name */
  124. #define INFO_RELID 1
  125. #define INFO_RELNAME 2
  126.     union {
  127.     ObjectId info_id;    /* relation object id */
  128.     Name     info_name;    /* relation name */
  129.     } i;
  130. } RelationBuildDescInfo;
  131.  
  132. typedef struct relidcacheent {
  133.     ObjectId reloid;
  134.     Relation reldesc;
  135. } RelIdCacheEnt;
  136. typedef struct relnamecacheent {
  137.     NameData relname;
  138.     Relation reldesc;
  139. } RelNameCacheEnt;
  140.  
  141. char *BuildDescInfoError ARGS((RelationBuildDescInfo buildinfo ));
  142. HeapTuple ScanPgRelation ARGS((RelationBuildDescInfo buildinfo ));
  143. void RelationBuildTupleDesc ARGS((
  144.     RelationBuildDescInfo buildinfo,
  145.     Relation relation,
  146.     AttributeTupleForm attp,
  147.     u_int natts
  148. ));
  149. Relation RelationBuildDesc ARGS((RelationBuildDescInfo buildinfo ));
  150. private void formrdesc ARGS((
  151.     char *relationName,
  152.     u_int natts,
  153.     AttributeTupleFormData att []
  154. ));
  155. private void RelationFlushIndexes ARGS((
  156.     Relation *relation,
  157.     ObjectId accessMethodId
  158. ));
  159.  
  160. /* -----------------
  161.  *    macros to manipulate name cache and id cache
  162.  * -----------------
  163.  */
  164. #define RelationCacheInsert(RELATION)    \
  165.     {   RelIdCacheEnt *idhentry; RelNameCacheEnt *namehentry; \
  166.     Name relname; ObjectId reloid; Boolean found; \
  167.     relname = &(RELATION->rd_rel->relname); \
  168.     namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
  169.                                &relname->data[0], \
  170.                            HASH_ENTER, \
  171.                            &found); \
  172.     if (namehentry == NULL) { \
  173.         elog(FATAL, "can't insert into relation descriptor cache"); \
  174.       } \
  175.     if (found && !IsBootstrapProcessingMode()) { \
  176.         /* used to give notice -- now just keep quiet */ ; \
  177.       } \
  178.     namehentry->reldesc = RELATION; \
  179.     reloid = RELATION->rd_id; \
  180.     idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
  181.                            (char *)&reloid, \
  182.                            HASH_ENTER, \
  183.                            &found); \
  184.     if (idhentry == NULL) { \
  185.         elog(FATAL, "can't insert into relation descriptor cache"); \
  186.       } \
  187.     if (found && !IsBootstrapProcessingMode()) { \
  188.         /* used to give notice -- now just keep quiet */ ; \
  189.       } \
  190.     idhentry->reldesc = RELATION; \
  191.     }
  192. #define RelationNameCacheLookup(NAME, RELATION)    \
  193.     {   RelNameCacheEnt *hentry; Boolean found; \
  194.     hentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
  195.                            (char *)NAME,HASH_FIND,&found); \
  196.     if (hentry == NULL) { \
  197.         elog(FATAL, "error in CACHE"); \
  198.       } \
  199.     if (found) { \
  200.         RELATION = hentry->reldesc; \
  201.       } \
  202.     else { \
  203.         RELATION = NULL; \
  204.       } \
  205.     }
  206. #define RelationIdCacheLookup(ID, RELATION)    \
  207.     {   RelIdCacheEnt *hentry; Boolean found; \
  208.     hentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
  209.                          (char *)&(ID),HASH_FIND, &found); \
  210.     if (hentry == NULL) { \
  211.         elog(FATAL, "error in CACHE"); \
  212.       } \
  213.     if (found) { \
  214.         RELATION = hentry->reldesc; \
  215.       } \
  216.     else { \
  217.         RELATION = NULL; \
  218.       } \
  219.     }
  220. #define RelationCacheDelete(RELATION)    \
  221.     {   RelNameCacheEnt *namehentry; RelIdCacheEnt *idhentry; \
  222.     Name relname; ObjectId reloid; Boolean found; \
  223.     relname = &(RELATION->rd_rel->relname); \
  224.     namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
  225.                                &relname->data[0], \
  226.                            HASH_REMOVE, \
  227.                            &found); \
  228.     if (namehentry == NULL) { \
  229.         elog(FATAL, "can't delete from relation descriptor cache"); \
  230.       } \
  231.     if (!found) { \
  232.         elog(NOTICE, "trying to delete a reldesc that does not exist."); \
  233.       } \
  234.     reloid = RELATION->rd_id; \
  235.     idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
  236.                            (char *)&reloid, \
  237.                            HASH_REMOVE, &found); \
  238.     if (idhentry == NULL) { \
  239.         elog(FATAL, "can't delete from relation descriptor cache"); \
  240.       } \
  241.     if (!found) { \
  242.         elog(NOTICE, "trying to delete a reldesc that does not exist."); \
  243.       } \
  244.     }
  245.  
  246. /* ----------------------------------------------------------------
  247.  *    RelationIdGetRelation() and RelationNameGetRelation()
  248.  *            support functions
  249.  * ----------------------------------------------------------------
  250.  */
  251.  
  252. /* --------------------------------
  253.  *    BuildDescInfoError returns a string appropriate to
  254.  *    the buildinfo passed to it
  255.  * --------------------------------
  256.  */
  257.  
  258. char *
  259. BuildDescInfoError(buildinfo)
  260.     RelationBuildDescInfo buildinfo;
  261. {
  262.     static char errBuf[64];
  263.  
  264.     bzero(errBuf, sizeof(errBuf));
  265.     switch(buildinfo.infotype) {
  266.     case INFO_RELID:
  267.     sprintf(errBuf, "(relation id %d)", buildinfo.i.info_id);
  268.     break;
  269.     case INFO_RELNAME:
  270.     sprintf(errBuf, "(relation name %s)", buildinfo.i.info_name);
  271.     break;
  272.     }
  273.  
  274.     return errBuf;
  275. }
  276.  
  277. /* --------------------------------
  278.  *    ScanPgRelation
  279.  *
  280.  *    this is used by RelationBuildDesc to find a pg_relation
  281.  *    tuple matching either a relation name or a relation id
  282.  *    as specified in buildinfo.
  283.  *
  284.  *    ADD INDEXING HERE
  285.  * --------------------------------
  286.  */
  287. HeapTuple
  288. ScanPgRelation(buildinfo)   
  289.     RelationBuildDescInfo buildinfo;    
  290. {
  291.     HeapTuple     pg_relation_tuple;
  292.     HeapTuple     return_tuple;
  293.     Relation     pg_relation_desc;
  294.     HeapScanDesc pg_relation_scan;
  295.     ScanKeyData     key;
  296.     Buffer     buf;
  297.     
  298.     /* ----------------
  299.      *    form a scan key
  300.      * ----------------
  301.      */
  302.     switch (buildinfo.infotype) {
  303.     case INFO_RELID:
  304.     ScanKeyEntryInitialize(&key.data[0], 0,
  305.                            ObjectIdAttributeNumber,
  306.                            ObjectIdEqualRegProcedure,
  307.                            ObjectIdGetDatum(buildinfo.i.info_id));
  308.     break;
  309.  
  310.     case INFO_RELNAME:
  311.     ScanKeyEntryInitialize(&key.data[0], 0,
  312.                            RelationNameAttributeNumber,
  313.                            Character16EqualRegProcedure,
  314.                            NameGetDatum(buildinfo.i.info_name));
  315.     break;
  316.  
  317.     default:
  318.     elog(WARN, "ScanPgRelation: bad buildinfo");
  319.     return NULL;
  320.     break;
  321.     }
  322.     
  323.     /* ----------------
  324.      *    open pg_relation and fetch a tuple
  325.      * ----------------
  326.      */
  327.     pg_relation_desc =  heap_openr(RelationRelationName);
  328.     RelationSetLockForRead(pg_relation_desc);
  329.     pg_relation_scan =
  330.     heap_beginscan(pg_relation_desc, 0, NowTimeQual, 1, &key);
  331.     pg_relation_tuple = heap_getnext(pg_relation_scan, 0, &buf);
  332.  
  333.     /* ----------------
  334.      *    get set to return tuple
  335.      * ----------------
  336.      */
  337.     if (! HeapTupleIsValid(pg_relation_tuple)) {
  338.     return_tuple = pg_relation_tuple;
  339.     } else {
  340.     /* ------------------
  341.      *  a satanic bug used to live here: pg_relation_tuple used to be
  342.      *  returned here without having the corresponding buffer pinned.
  343.      *  so when the buffer gets replaced, all hell breaks loose.
  344.      *  this bug is discovered and killed by wei on 9/27/91.
  345.      * -------------------
  346.      */
  347.     return_tuple = (HeapTuple)palloc(pg_relation_tuple->t_len);
  348.     bcopy(pg_relation_tuple, return_tuple, pg_relation_tuple->t_len);
  349.     ReleaseBuffer(buf);
  350.     }
  351.  
  352.     /* all done */
  353.     heap_endscan(pg_relation_scan);
  354.     RelationUnsetLockForRead(pg_relation_desc);
  355.     heap_close(pg_relation_desc);
  356.  
  357.     return return_tuple;
  358. }
  359.  
  360. /* ----------------
  361.  *    AllocateRelationDesc
  362.  *
  363.  *    This is used to allocate memory for a new relation descriptor
  364.  *    and initialize the rd_rel field.
  365.  * ----------------
  366.  */
  367. Relation
  368. AllocateRelationDesc(natts, relp)
  369.     u_int        natts;
  370.     RelationTupleForm    relp;
  371. {
  372.     Relation         relation;
  373.     int            len;
  374.     RelationTupleForm   relationTupleForm;
  375.     
  376.     /* ----------------
  377.      *  allocate space for the relation tuple form
  378.      * ----------------
  379.      */
  380.     relationTupleForm = (RelationTupleForm)
  381.     palloc(sizeof (RuleLock) + sizeof *relation->rd_rel);
  382.     
  383.     bcopy((char *)relp, (char *)relationTupleForm, sizeof *relp);
  384.     
  385.     /* ----------------
  386.      *    allocate space for new relation descriptor, including
  387.      *  the tuple descriptor and the index strategy and support pointers
  388.      * ----------------
  389.      */
  390.     len = sizeof(RelationData) + 
  391.     ((int)natts - 1) * sizeof(relation->rd_att) + /* var len struct */
  392.         sizeof(IndexStrategy)
  393.         + sizeof(RegProcedure *) + 10;    /* + 10 is voodoo XXX mao */
  394.     
  395.     relation = (Relation) palloc(len);
  396.     
  397.     /* ----------------
  398.      *    clear new reldesc and initialize relation tuple form
  399.      * ----------------
  400.      */
  401.     bzero((char *)relation, len);
  402.     relation->rd_rel = relationTupleForm;
  403.  
  404.     return relation;
  405. }
  406.  
  407. /* --------------------------------
  408.  *    RelationBuildTupleDesc
  409.  *
  410.  *    Form the relation's tuple descriptor from information in
  411.  *    the pg_attribute system catalog.
  412.  *
  413.  *    ADD INDEXING HERE
  414.  * --------------------------------
  415.  */
  416. void
  417. RelationBuildTupleDesc(buildinfo, relation, attp, natts) 
  418.     RelationBuildDescInfo buildinfo;    
  419.     Relation          relation;
  420.     AttributeTupleForm      attp;
  421.     u_int          natts;
  422. {
  423.     HeapTuple    pg_attribute_tuple;
  424.     Relation     pg_attribute_desc;
  425.     HeapScanDesc pg_attribute_scan;
  426.     ScanKeyData     key;
  427.     int         i;
  428.     int         need;
  429.  
  430.     /* ----------------
  431.      *    form a scan key
  432.      * ----------------
  433.      */
  434.     ScanKeyEntryInitialize(&key.data[0], 0, 
  435.                            AttributeRelationIdAttributeNumber,
  436.                            ObjectIdEqualRegProcedure,
  437.                            ObjectIdGetDatum(relation->rd_id));
  438.     
  439.     /* ----------------
  440.      *    open pg_attribute and begin a scan
  441.      * ----------------
  442.      */
  443.     pg_attribute_desc = heap_openr(AttributeRelationName);
  444.     pg_attribute_scan =
  445.     heap_beginscan(pg_attribute_desc, 0, NowTimeQual, 1, &key);
  446.     
  447.     /* ----------------
  448.      *    add attribute data to relation->rd_att
  449.      * ----------------
  450.      */
  451.     need = natts;
  452.     pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0, (Buffer *) NULL);
  453.     while (HeapTupleIsValid(pg_attribute_tuple) && need > 0) {
  454.  
  455.     attp = (AttributeTupleForm)
  456.         HeapTupleGetForm(pg_attribute_tuple);
  457.  
  458.     if (attp->attnum > 0) {
  459.  
  460.         relation->rd_att.data[attp->attnum - 1] = (Attribute)
  461.         palloc(sizeof (RuleLock) + sizeof *relation->rd_att.data[0]);
  462.  
  463.         bcopy((char *) attp,
  464.           (char *) relation->rd_att.data[attp->attnum - 1],
  465.           sizeof *relation->rd_att.data[0]);
  466.  
  467.         need--;
  468.     }
  469.     pg_attribute_tuple = heap_getnext(pg_attribute_scan,
  470.                       0, (Buffer *) NULL);
  471.     }
  472.  
  473.     if (need > 0)
  474.     elog(WARN, "catalog is missing %d attribute%s for relid %d",
  475.         natts - need, ((natts - need) == 1 ? "" : "s"),
  476.         relation->rd_id);
  477.  
  478.     /* ----------------
  479.      *    end the scan and close the attribute relation
  480.      * ----------------
  481.      */
  482.     heap_endscan(pg_attribute_scan);
  483.     heap_close(pg_attribute_desc);
  484. }
  485.  
  486. /* kai: Moved this declaration outside of the following function, as some
  487.    functions miss it. */
  488. extern GlobalMemory CacheCxt;
  489. /* --------------------------------
  490.  *    RelationBuildDesc
  491.  *    
  492.  *    To build a relation descriptor, we have to allocate space,
  493.  *    open the underlying unix file and initialize the following
  494.  *    fields:
  495.  *
  496.  *  File           rd_fd;     open file descriptor
  497.  *  int                    rd_nblocks;   number of blocks in rel 
  498.  *                     it will be set in ambeginscan()
  499.  *  uint16           rd_refcnt;     reference count
  500.  *  AccessMethodTupleForm  rd_am;     AM tuple
  501.  *  RelationTupleForm       rd_rel;     RELATION tuple
  502.  *  ObjectId           rd_id;     relations's object id 
  503.  *  Pointer           lockInfo;     ptr. to misc. info.
  504.  *  TupleDescriptorData       rd_att;     tuple desciptor
  505.  *
  506.  *    Note: rd_ismem (rel is in-memory only) is currently unused
  507.  *      by any part of the system.  someday this will indicate that
  508.  *    the relation lives only in the main-memory buffer pool
  509.  *    -cim 2/4/91
  510.  * --------------------------------
  511.  */
  512. Relation
  513. RelationBuildDesc(buildinfo)
  514.     RelationBuildDescInfo buildinfo;
  515. {
  516.     File        fd;
  517.     Relation        relation;
  518.     u_int        natts;
  519.     ObjectId        relid;
  520.     ObjectId        relam;
  521.     RelationTupleForm    relp;
  522.     AttributeTupleForm    attp = NULL;
  523.     ObjectId        attrioid; /* attribute relation index relation oid */
  524.  
  525.     MemoryContext    oldcxt;
  526.     
  527.     HeapTuple        pg_relation_tuple;
  528.     
  529.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  530.  
  531.     /* ----------------
  532.      *    find the tuple in pg_relation corresponding to the given relation id
  533.      * ----------------
  534.      */
  535.     pg_relation_tuple = ScanPgRelation(buildinfo);
  536.  
  537.     /* ----------------
  538.      *    if no such tuple exists, return NULL
  539.      * ----------------
  540.      */
  541.     if (! HeapTupleIsValid(pg_relation_tuple)) {
  542.     
  543.     MemoryContextSwitchTo(oldcxt); 
  544.      
  545.     return NULL;
  546.     }
  547.  
  548.     /* ----------------
  549.      *    get information from the pg_relation_tuple
  550.      * ----------------
  551.      */
  552.     relid = pg_relation_tuple->t_oid;
  553.     relp = (RelationTupleForm) GETSTRUCT(pg_relation_tuple);
  554.     natts = relp->relnatts;
  555.     
  556.     /* ----------------
  557.      *    allocate storage for the relation descriptor,
  558.      *  initialize relation->rd_rel and get the access method id.
  559.      * ----------------
  560.      */
  561.     relation = AllocateRelationDesc(natts, relp);
  562.     relam = relation->rd_rel->relam;
  563.     
  564.     /* ----------------
  565.      *    initialize the relation's relation id (relation->rd_id)
  566.      * ----------------
  567.      */
  568.     relation->rd_id = relid;
  569.  
  570.     /* ----------------
  571.      *    initialize relation->rd_refcnt
  572.      * ----------------
  573.      */
  574.     RelationSetReferenceCount(relation, 1);
  575.     
  576.     /* ----------------
  577.      *   normal relations are not nailed into the cache
  578.      * ----------------
  579.      */
  580.     relation->rd_isnailed = false;
  581.  
  582.     /* ----------------
  583.      *    initialize the access method information (relation->rd_am)
  584.      * ----------------
  585.      */
  586.     if (ObjectIdIsValid(relam)) {
  587.     relation->rd_am = (AccessMethodTupleForm)
  588.         AccessMethodObjectIdGetAccessMethodTupleForm(relam);
  589.     }
  590.  
  591.     /* ----------------
  592.      *    initialize the tuple descriptor (relation->rd_att).
  593.      *  remember, rd_att is an array of attribute pointers that lives
  594.      *  off the end of the relation descriptor structure so space was
  595.      *  already allocated for it by AllocateRelationDesc.
  596.      * ----------------
  597.      */
  598.     RelationBuildTupleDesc(buildinfo, relation, attp, natts);
  599.  
  600.     /* ----------------
  601.      *    initialize index strategy and support information for this relation
  602.      * ----------------
  603.      */
  604.     if (ObjectIdIsValid(relam)) {
  605.     IndexedAccessMethodInitialize(relation);
  606.     }
  607.  
  608.     /* ----------------
  609.      *    initialize the relation lock manager information
  610.      * ----------------
  611.      */
  612.     RelationInitLockInfo(relation); /* see lmgr.c */
  613.     
  614.     /* ----------------
  615.      *    open the relation and assign the file descriptor returned
  616.      *  by the storage manager code to rd_fd.
  617.      * ----------------
  618.      */
  619.     fd = smgropen(relp->relsmgr, relation);
  620.     
  621.     Assert (fd >= -1);
  622.     if (fd == -1)
  623.     elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
  624.          &relp->relname);
  625.     
  626.     relation->rd_fd = fd;
  627.     
  628.     /* ----------------
  629.      *    insert newly created relation into proper relcaches,
  630.      *  restore memory context and return the new reldesc.
  631.      * ----------------
  632.      */
  633.     
  634.     RelationCacheInsert(relation);
  635.  
  636.     /* -------------------
  637.      *  free the memory allocated for pg_relation_tuple
  638.      * -------------------
  639.      */
  640.     pfree(pg_relation_tuple);
  641.  
  642.     MemoryContextSwitchTo(oldcxt);
  643.     
  644.     return relation;
  645. }
  646.  
  647. IndexedAccessMethodInitialize(relation)
  648.     Relation relation;
  649. {
  650.     IndexStrategy     strategy;
  651.     RegProcedure    *support;
  652.     int            natts;
  653.     int         stratSize;
  654.     int            supportSize;
  655.     uint16         relamstrategies;
  656.     uint16        relamsupport;
  657.     
  658.     natts = relation->rd_rel->relnatts;
  659.     relamstrategies = relation->rd_am->amstrategies;
  660.     stratSize = AttributeNumberGetIndexStrategySize(natts, relamstrategies);
  661.     strategy = (IndexStrategy) palloc(stratSize);
  662.     relamsupport = relation->rd_am->amsupport;
  663.  
  664.     if (relamsupport > 0) {
  665.     supportSize = natts * (relamsupport * sizeof (RegProcedure));
  666.     support = (RegProcedure *) palloc(supportSize);
  667.     } else {
  668.     support = (RegProcedure *) NULL;
  669.     }
  670.  
  671.     IndexSupportInitialize(strategy, support,
  672.                     relation->rd_att.data[0]->attrelid,
  673.                     relation->rd_rel->relam,
  674.                 relamstrategies, relamsupport, natts);
  675.  
  676.     RelationSetIndexSupport(relation, strategy, support);
  677. }
  678.  
  679. /* --------------------------------
  680.  *    formrdesc
  681.  *
  682.  *    This is a special version of RelationBuildDesc()
  683.  *    used by RelationInitialize() in initializing the
  684.  *    relcache.  The system relation descriptors built
  685.  *    here are all nailed in the descriptor caches, for
  686.  *    bootstraping.
  687.  * --------------------------------
  688.  */
  689. private void
  690. formrdesc(relationName, natts, att)
  691.     char        *relationName;
  692.     u_int        natts;
  693.     AttributeTupleFormData att[];
  694. {
  695.     Relation    relation;
  696.     int        fd;
  697.     int        len;
  698.     int        i;
  699.     char    *relpath();
  700.     Relation    publicCopy;
  701.     
  702.     /* ----------------
  703.      *    allocate new relation desc
  704.      * ----------------
  705.      */
  706.     len = sizeof *relation + ((int)natts - 1) * sizeof relation->rd_att;
  707.     relation = (Relation) palloc(len);
  708.     bzero((char *)relation, len);
  709.     
  710.     /* ----------------
  711.      *    don't open the unix file yet..
  712.      * ----------------
  713.      */
  714.     relation->rd_fd = -1;
  715.     
  716.     /* ----------------
  717.      *    initialize reference count
  718.      * ----------------
  719.      */
  720.     RelationSetReferenceCount(relation, 1);
  721.  
  722.     /* ----------------
  723.      *    initialize relation tuple form
  724.      * ----------------
  725.      */
  726.     relation->rd_rel = (RelationTupleForm)
  727.     palloc(sizeof (RuleLock) + sizeof *relation->rd_rel);
  728.  
  729.     bzero(relation->rd_rel, sizeof(struct RelationTupleFormD));
  730.  
  731.     strncpy(&relation->rd_rel->relname, relationName, sizeof(NameData));
  732.  
  733.     /*
  734.      *  For debugging purposes, it's important to distinguish between
  735.      *  shared and non-shared relations, even at bootstrap time.  There's
  736.      *  code in the buffer manager that traces allocations that has to
  737.      *  know about this.
  738.      */
  739.  
  740.     if (issystem(relationName)) {
  741.     relation->rd_rel->relowner = 6;            /* XXX use sym const */
  742.     relation->rd_rel->relisshared =
  743.         NameIsSharedSystemRelationName((Name)relationName);
  744.     } else {
  745.     relation->rd_rel->relowner = InvalidObjectId;    /* XXX incorrect*/
  746.     relation->rd_rel->relisshared = false;
  747.     }
  748.  
  749.     relation->rd_rel->relpages = 1;            /* XXX */
  750.     relation->rd_rel->reltuples = 1;            /* XXX */
  751.     relation->rd_rel->relkind = 'r';
  752.     relation->rd_rel->relarch = 'n';
  753.     relation->rd_rel->relnatts = (uint16) natts;
  754.     relation->rd_isnailed = true;
  755.  
  756.     /* ----------------
  757.      *    initialize tuple desc info
  758.      * ----------------
  759.      */
  760.     for (i = 0; i < natts; i++) {
  761.     relation->rd_att.data[i] = (Attribute)
  762.         palloc(sizeof (RuleLock) + sizeof *relation->rd_att.data[0]);
  763.     
  764.     bzero((char *)relation->rd_att.data[i], sizeof (RuleLock) +
  765.           sizeof *relation->rd_att.data[0]);
  766.     bcopy((char *)&att[i], (char *)relation->rd_att.data[i],
  767.           sizeof *relation->rd_att.data[0]);
  768.     }
  769.     
  770.     /* ----------------
  771.      *    initialize relation id
  772.      * ----------------
  773.      */
  774.     relation->rd_id = relation->rd_att.data[0]->attrelid;
  775.     
  776.     /* ----------------
  777.      *    add new reldesc to relcache
  778.      * ----------------
  779.      */
  780.     RelationCacheInsert(relation);
  781.     /*
  782.      * Determining this requires a scan on pg_relation, but to do the
  783.      * scan the rdesc for pg_relation must already exist.  Therefore
  784.      * we must do the check (and possible set) after cache insertion.
  785.      */
  786.     relation->rd_rel->relhasindex =
  787.     CatalogHasIndex(relationName, relation->rd_id);
  788. }
  789.  
  790.  
  791. /* ----------------------------------------------------------------
  792.  *         Relation Descriptor Lookup Interface
  793.  * ----------------------------------------------------------------
  794.  */
  795.  
  796. /* --------------------------------
  797.  *    RelationIdCacheGetRelation
  798.  *
  799.  *    only try to get the reldesc by looking up the cache
  800.  *    do not go to the disk.  this is used by BlockPrepareFile()
  801.  *    and RelationIdGetRelation below.
  802.  * --------------------------------
  803.  */
  804. Relation
  805. RelationIdCacheGetRelation(relationId)
  806.     ObjectId    relationId;
  807. {
  808.     Relation    rd;
  809.  
  810.     RelationIdCacheLookup(relationId, rd);
  811.     
  812.     if (RelationIsValid(rd)) {
  813.     if (rd->rd_fd == -1) {
  814.         rd->rd_fd = smgropen(rd->rd_rel->relsmgr, rd);
  815.         Assert(rd->rd_fd != -1);
  816.     }
  817.     
  818.     RelationIncrementReferenceCount(rd);
  819.     RelationSetLockForDescriptorOpen(rd);
  820.     
  821.     }
  822.     
  823.     return(rd);
  824. }
  825.  
  826. /* --------------------------------
  827.  *    RelationNameCacheGetRelation
  828.  * --------------------------------
  829.  */
  830. Relation
  831. RelationNameCacheGetRelation(relationName)
  832.     Name    relationName;
  833. {
  834.     Relation    rd;
  835.     NameData    name;
  836.  
  837.     /* make sure that the name key used for hash lookup is properly
  838.        null-padded */
  839.     bzero(&name, sizeof(NameData));
  840.     strncpy(&name, relationName, sizeof(NameData));
  841.     RelationNameCacheLookup(&name, rd);
  842.     
  843.     if (RelationIsValid(rd)) {
  844.     if (rd->rd_fd == -1) {
  845.         rd->rd_fd = smgropen(rd->rd_rel->relsmgr, rd);
  846.         Assert(rd->rd_fd != -1);
  847.     }
  848.     
  849.     RelationIncrementReferenceCount(rd);
  850.     RelationSetLockForDescriptorOpen(rd);
  851.     
  852.     }
  853.     
  854.     return(rd);
  855. }
  856.  
  857. /* --------------------------------
  858.  *    RelationIdGetRelation
  859.  *
  860.  *    return a relation descriptor based on its id.
  861.  *    return a cached value if possible
  862.  * --------------------------------
  863.  */
  864. Relation
  865. RelationIdGetRelation(relationId)
  866.     ObjectId    relationId;
  867. {
  868.     Relation          rd;
  869.     RelationBuildDescInfo buildinfo;
  870.     
  871.     /* ----------------
  872.      *    increment access statistics
  873.      * ----------------
  874.      */
  875.     IncrHeapAccessStat(local_RelationIdGetRelation);
  876.     IncrHeapAccessStat(global_RelationIdGetRelation);
  877.  
  878.     /* ----------------
  879.      *    first try and get a reldesc from the cache
  880.      * ----------------
  881.      */
  882.     rd = RelationIdCacheGetRelation(relationId);
  883.     if (RelationIsValid(rd))
  884.        return rd;
  885.     
  886.     /* ----------------
  887.      *    no reldesc in the cache, so have RelationBuildDesc()
  888.      *  build one and add it.
  889.      * ----------------
  890.      */
  891.     buildinfo.infotype =  INFO_RELID;
  892.     buildinfo.i.info_id = relationId;
  893.     
  894.     rd = RelationBuildDesc(buildinfo);
  895.     return
  896.     rd;
  897. }
  898.  
  899. /* --------------------------------
  900.  *    RelationNameGetRelation
  901.  *
  902.  *    return a relation descriptor based on its name.
  903.  *    return a cached value if possible
  904.  * --------------------------------
  905.  */
  906. Relation
  907. RelationNameGetRelation(relationName)
  908.     Name        relationName;
  909. {
  910.     Relation          rd;
  911.     RelationBuildDescInfo buildinfo;
  912.     
  913.     /* ----------------
  914.      *    increment access statistics
  915.      * ----------------
  916.      */
  917.     IncrHeapAccessStat(local_RelationNameGetRelation);
  918.     IncrHeapAccessStat(global_RelationNameGetRelation);
  919.  
  920.     /* ----------------
  921.      *    first try and get a reldesc from the cache
  922.      * ----------------
  923.      */
  924.     rd = RelationNameCacheGetRelation(relationName);
  925.     if (RelationIsValid(rd))
  926.        return rd;
  927.     
  928.     /* ----------------
  929.      *    no reldesc in the cache, so have RelationBuildDesc()
  930.      *  build one and add it.
  931.      * ----------------
  932.      */
  933.     buildinfo.infotype =    INFO_RELNAME;
  934.     buildinfo.i.info_name = relationName;
  935.     
  936.     rd = RelationBuildDesc(buildinfo);
  937.     return
  938.     rd;
  939. }
  940.  
  941. /* ----------------
  942.  *    old "getreldesc" interface.
  943.  * ----------------
  944.  */
  945. Relation
  946. getreldesc(relationName)
  947.     Name  relationName;
  948. {
  949.     /* ----------------
  950.      *    increment access statistics
  951.      * ----------------
  952.      */
  953.     IncrHeapAccessStat(local_getreldesc);
  954.     IncrHeapAccessStat(global_getreldesc);
  955.     
  956.     return (Relation)
  957.     RelationNameGetRelation(relationName);
  958. }
  959.  
  960. /* ----------------------------------------------------------------
  961.  *        cache invalidation support routines
  962.  * ----------------------------------------------------------------
  963.  */
  964.  
  965. /* --------------------------------
  966.  *    RelationClose - close an open relation
  967.  * --------------------------------
  968.  */
  969. void
  970. RelationClose(relation)
  971.     Relation    relation;
  972. {
  973.     /* Note: no locking manipulations needed */
  974.     RelationDecrementReferenceCount(relation);
  975. }
  976.  
  977. /* --------------------------------
  978.  *    RelationFlushRelation
  979.  * --------------------------------
  980.  */
  981. /**** xxref:
  982.  *           RelationIdInvalidateRelationCacheByRelationId
  983.  *           RelationFlushIndexes
  984.  ****/
  985. void
  986. RelationFlushRelation(relation, onlyFlushReferenceCountZero)
  987.     Relation    relation;
  988.     bool    onlyFlushReferenceCountZero;
  989. {
  990.     int            i;
  991.     Attribute        *p;
  992.     MemoryContext    oldcxt;
  993.     
  994.     if (relation->rd_isnailed) {
  995.     /* this is a nailed special relation for bootstraping */
  996.     return;
  997.     }
  998.     
  999.     if (!onlyFlushReferenceCountZero || 
  1000.     RelationHasReferenceCountZero(relation)) {
  1001.     
  1002.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  1003.     
  1004.     RelationCacheDelete(relation);
  1005.     
  1006.     FileInvalidate(RelationGetSystemPort(relation));
  1007.     
  1008.     i = relation->rd_rel->relnatts - 1;
  1009.     p = &relation->rd_att.data[i];
  1010.     while ((i -= 1) >= 0) {
  1011.         pfree((char *)*p--);
  1012.     }
  1013.     
  1014.     pfree((char *)RelationGetLockInfo(relation));
  1015.     pfree((char *)RelationGetRelationTupleForm(relation));
  1016.     pfree((char *)relation);
  1017.     
  1018.     MemoryContextSwitchTo(oldcxt);
  1019.     }
  1020. }
  1021.  
  1022. /* --------------------------------
  1023.  *    RelationIdInvalidateRelationCacheByRelationId
  1024.  * --------------------------------
  1025.  */
  1026. /**** xxref:
  1027.  *           CacheIdInvalidate
  1028.  ****/
  1029. void
  1030. RelationIdInvalidateRelationCacheByRelationId(relationId)
  1031.     ObjectId    relationId;
  1032. {
  1033.     Relation    relation;
  1034.     
  1035.     RelationIdCacheLookup(relationId, relation);
  1036.     
  1037.     if (PointerIsValid(relation)) {
  1038.     /* Assert(RelationIsValid(relation)); */
  1039.     /*
  1040.      * The boolean onlyFlushReferenceCountZero in RelationFlushReln()
  1041.      * should be set to true when we are incrementing the command
  1042.      * counter and to false when we are starting a new xaction.  This
  1043.      * can be determined by checking the current xaction status.
  1044.      */
  1045.     RelationFlushRelation(relation, CurrentXactInProgress());
  1046.     }
  1047. }
  1048.  
  1049. /* --------------------------------
  1050.  *    RelationIdInvalidateRelationCacheByAccessMethodId
  1051.  *
  1052.  *    RelationFlushIndexes is needed for use with HashTableWalk..
  1053.  * --------------------------------
  1054.  */
  1055. private void
  1056. RelationFlushIndexes(r, accessMethodId)
  1057.     Relation    *r;
  1058.     ObjectId    accessMethodId;
  1059. {
  1060.     Relation relation = *r;
  1061.  
  1062.     if (!RelationIsValid(relation)) {
  1063.     elog(NOTICE, "inval call to RFI");
  1064.     return;
  1065.     }
  1066.  
  1067.     if (relation->rd_rel->relkind == 'i' &&    /* XXX style */
  1068.     (!ObjectIdIsValid(accessMethodId) ||
  1069.      relation->rd_rel->relam == accessMethodId))
  1070.     {
  1071.         RelationFlushRelation(relation, false);
  1072.     }
  1073. }
  1074.  
  1075. /**** xxref:
  1076.  *           CacheIdInvalidate
  1077.  ****/
  1078. void
  1079. RelationIdInvalidateRelationCacheByAccessMethodId(accessMethodId)
  1080.     ObjectId    accessMethodId;
  1081. {
  1082. # if 0
  1083.     /*
  1084.      *  25 aug 1992:  mao commented out the ht walk below.  it should be
  1085.      *  doing the right thing, in theory, but flushing reldescs for index
  1086.      *  relations apparently doesn't work.  we want to cut 4.0.1, and i
  1087.      *  don't want to introduce new bugs.  this code never executed before,
  1088.      *  so i'm turning it off for now.  after the release is cut, i'll
  1089.      *  fix this up.
  1090.      */
  1091.  
  1092.     HashTableWalk(RelationNameCache, RelationFlushIndexes,
  1093.           accessMethodId);
  1094. # else
  1095.     return;
  1096. # endif
  1097. }
  1098.  
  1099. /* --------------------------------
  1100.  *    RelationCacheInvalidate
  1101.  * --------------------------------
  1102.  */
  1103. /**** xxref:
  1104.  *           ResetSystemCaches
  1105.  ****/
  1106. void
  1107. RelationCacheInvalidate(onlyFlushReferenceCountZero)
  1108.     bool onlyFlushReferenceCountZero;
  1109. {
  1110.     HashTableWalk(RelationNameCache, RelationFlushRelation, 
  1111.           onlyFlushReferenceCountZero);
  1112. }
  1113.  
  1114. /* --------------------------------
  1115.  *    RelationRegisterRelation
  1116.  * --------------------------------
  1117.  */
  1118. /**** xxref:
  1119.  *           RelationRegisterTempRel
  1120.  ****/
  1121. void
  1122. RelationRegisterRelation(relation)
  1123.     Relation    relation;
  1124. {
  1125.     extern GlobalMemory CacheCxt;
  1126.     MemoryContext       oldcxt;
  1127.     
  1128.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  1129.     
  1130.     if (oldcxt != (MemoryContext)CacheCxt) 
  1131.     elog(NOIND,"RelationRegisterRelation: WARNING: Context != CacheCxt");
  1132.     
  1133.     RelationCacheInsert(relation);
  1134.     
  1135.     RelationInitLockInfo(relation);
  1136.     
  1137.     MemoryContextSwitchTo(oldcxt);
  1138. }
  1139.  
  1140. /* -----------------------------------
  1141.  *  RelationRegisterTempRel
  1142.  *
  1143.  *      Register a temporary relation created by another backend
  1144.  *      only called in parallel mode.
  1145.  * ----------------------------------
  1146.  */
  1147. /**** xxref:
  1148.  *           <apparently-unused>
  1149.  ****/
  1150. void
  1151. RelationRegisterTempRel(temprel)
  1152.     Relation temprel;
  1153. {
  1154.     extern GlobalMemory CacheCxt;
  1155.     MemoryContext       oldcxt;
  1156.     Relation         rd;
  1157.     
  1158.     /* ----------------------------------------
  1159.      *  see if the temprel is created by the current backend
  1160.      *  and therefore is already in the hast table
  1161.      * ----------------------------------------
  1162.      */
  1163.     RelationIdCacheLookup(temprel->rd_id, rd);
  1164.     
  1165.     if (RelationIsValid(rd))
  1166.     return;
  1167.     
  1168.     /* ----------------------------------------
  1169.      *  the temprel is created by another backend, insert it into the 
  1170.      *  hash table
  1171.      * ----------------------------------------
  1172.      */
  1173.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  1174.     
  1175.     RelationRegisterRelation(temprel);
  1176.     
  1177.     MemoryContextSwitchTo(oldcxt);
  1178. }
  1179.  
  1180. /* --------------------------------
  1181.  *    RelationInitialize
  1182.  *
  1183.  *    This initializes the relation descriptor cache.
  1184.  * --------------------------------
  1185.  */
  1186.  
  1187. #define INITRELCACHESIZE    400
  1188.  
  1189. void 
  1190. RelationInitialize()
  1191. {
  1192.     extern GlobalMemory        CacheCxt;
  1193.     MemoryContext        oldcxt;
  1194.     HASHCTL            ctl;
  1195.  
  1196.     /* ----------------
  1197.      *    switch to cache memory context
  1198.      * ----------------
  1199.      */
  1200.     if (!CacheCxt)
  1201.     CacheCxt = CreateGlobalMemory("Cache");
  1202.     
  1203.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  1204.  
  1205.     /* ----------------
  1206.      *    create global caches
  1207.      * ----------------
  1208.      */
  1209.     bzero(&ctl, sizeof(ctl));
  1210.     ctl.keysize = sizeof(NameData);
  1211.     ctl.datasize = sizeof(Relation);
  1212.     RelationNameCache = hash_create(INITRELCACHESIZE, &ctl, HASH_ELEM);
  1213.     
  1214.     ctl.keysize = sizeof(ObjectId);
  1215.     ctl.hash = tag_hash;
  1216.     RelationIdCache = hash_create(INITRELCACHESIZE, &ctl, 
  1217.                   HASH_ELEM | HASH_FUNCTION);
  1218.     
  1219.     /* ----------------
  1220.      *    initialize the cache with pre-made relation descriptors
  1221.      *  for some of the more important system relations.  These
  1222.      *  relations should always be in the cache.
  1223.      * ----------------
  1224.      */
  1225. #define INIT_RELDESC(x) \
  1226.     formrdesc(SCHEMA_NAME(x), \
  1227.           SCHEMA_NATTS(x), \
  1228.           SCHEMA_DESC(x))
  1229.     
  1230.     INIT_RELDESC(pg_relation);
  1231.     INIT_RELDESC(pg_attribute);
  1232.     INIT_RELDESC(pg_proc);
  1233.     INIT_RELDESC(pg_type);
  1234.     INIT_RELDESC(pg_variable);
  1235.     INIT_RELDESC(pg_log);
  1236.     INIT_RELDESC(pg_time);
  1237.     
  1238.     MemoryContextSwitchTo(oldcxt);
  1239. }
  1240.